Skip to content

Scope down to manual-URL spine; make compose verifiable end-to-end - #6

Merged
scrumlord8 merged 4 commits into
mainfrom
ninerpride/outputs
Apr 18, 2026
Merged

Scope down to manual-URL spine; make compose verifiable end-to-end#6
scrumlord8 merged 4 commits into
mainfrom
ninerpride/outputs

Conversation

@scrumlord8

Copy link
Copy Markdown
Owner

Summary

Product decision from the PO: discovery depends on gated APIs (TikTok Research access, X paid-tier search) we can't guarantee, so stop pretending it's the spine. Treat "fresh input in, finished clip out" as the honest minimum viable truth and make the compose pipeline the solid thing the tool does.

  • README rewritten around the manual-URL flow. Quick Start, batch guide, and command reference all center on library import + compose. The discover/autopilot commands move to "Optional: API-gated discovery (experimental)" with explicit token caveats (TikTok Research gating, X API at $200/mo minimum). Stale claims removed. Python references stripped.
  • scripts/build-clips-from-urls.sh is the new primary batch path: 1 supplied sound URL + 3 supplied clip URLs → a self-contained clips/ folder with finished MP4s, source references, and a provenance manifest.
  • .github/workflows/build-clips.yml gains a mode selector — urls is the default; discovery is opt-in behind both repo secrets.
  • tests/e2e_url_to_clip.rs is a real end-to-end smoke test of library importcompose via a yt-dlp shim, so the manual-URL spine is verifiable in CI without network. Passes in ~7s.
  • .github/workflows/test.yml runs cargo test --all-targets on every push.
  • Committed demo fixtures (2s sine MP3, 3s color MP4) plus library/manifest.json so compose works on a fresh clone and the existing compose smoke test has real bytes.
  • Pre-existing test-compile bug fixed: duplicate #[cfg(test)] mod tests in src/media/downloader.rs was preventing cargo test from compiling at all. Renamed the second module to tests_url_detection.
  • src/config.rs gains a CAPCUT_YTDLP_PATH env override so tests can inject a yt-dlp shim. Production path unchanged.
  • .devcontainer/ rebuilt for Rust-only bootstrap (no Python toolchain), using capcut-cli deps install to fetch the standalone yt-dlp binary.
  • Secondary docs (.env.example, library/sounds/README.md, .devcontainer/post-create.sh) aligned with the new scope.

67 tests passing locally (66 unit + 1 e2e).

Test plan

  • cargo test --all-targets — 67 tests pass
  • ./target/release/capcut-cli deps check — reports ffmpeg + yt-dlp installed
  • tests/e2e_url_to_clip.rs — imports two fake URLs via a yt-dlp shim, composes them, asserts the output MP4 exists
  • scripts/build-clips-from-urls.sh — bash syntax check, error paths surface upstream CLI errors cleanly
  • .github/workflows/build-clips.ymlurls mode validates presence of all four URL inputs; discovery mode validates both token secrets
  • Manual run of build-clips Action in urls mode against real URLs (pending, needs user to trigger from GitHub mobile app)
  • Manual run of build-clips Action in discovery mode if/when TikTok Research + X Basic tokens are available

claude added 4 commits April 18, 2026 17:16
Two phone-friendly ways to run real discovery and produce three composed
MP4s alongside their source audio and clip assets:

- .github/workflows/build-clips.yml: manual-dispatch workflow that checks
  for API tokens, installs ffmpeg/yt-dlp, builds the CLI, runs discovery
  and compose via scripts/build-clips.sh, and uploads a clips/ artifact.
- .devcontainer/: Rust+Python devcontainer with a post-create step that
  wires yt-dlp into ~/.capcut-cli/bin and builds the release binary; pairs
  with `make clips` for one-command runs inside Codespaces.
- scripts/build-clips.sh: discovers one trending sound + three ranked X
  clips, imports each, composes clip_{1,2,3}.mp4, and stages the real
  source references plus a manifest.json under ./clips.
- README: documents both paths and the required repo/Codespace secrets.
The CLI is Rust-only; yt-dlp itself is distributed as a standalone Linux
binary by the upstream project, and 'deps install' already downloads it.
Using that path keeps Python off the install surface for both the Action
and the devcontainer.
Product decision: discovery depends on gated APIs (TikTok Research access,
X paid-tier search) whose availability we can't guarantee. Treat "fresh
input in, finished clip out" as the honest minimum viable truth and make
the compose pipeline the solid thing the tool does.

- README rewritten around the manual-URL flow. The Quick Start, batch
  guide, and command reference all center on library import + compose.
  The discover/autopilot commands are moved into an "Optional: API-gated
  discovery (experimental)" section with explicit caveats about token
  gating. Stale claims removed. Python references stripped.
- scripts/build-clips-from-urls.sh: primary batch path. Takes one
  supplied sound URL plus three supplied clip URLs and produces a
  self-contained clips/ folder with finished MP4s, source references,
  and a provenance manifest.
- .github/workflows/build-clips.yml: gains a mode selector; urls mode is
  the default, discovery mode is opt-in behind both repo secrets.
- tests/e2e_url_to_clip.rs: end-to-end smoke test that exercises the
  full library import → compose pipeline via a yt-dlp shim, so the
  honest minimum viable truth is verifiable without network access.
- .github/workflows/test.yml: runs cargo test --all-targets on every
  push so the spine stays provable in CI.
- library/manifest.json plus small synthetic demo fixtures under
  library/sounds/assets/snd_demo001 and library/clips/clp_demo001 so
  compose works immediately on a fresh clone and the compose smoke
  test has real bytes to exercise.
- src/config.rs: CAPCUT_YTDLP_PATH env override so tests can inject a
  yt-dlp shim. Production path unchanged.
- src/media/downloader.rs: merge two duplicate #[cfg(test)] mod tests
  blocks that were preventing cargo test from compiling at all.
- .gitignore: trimmed Python section, whitelisted the committed demo
  fixtures, anchored the batch-output ignore to the repo root.
- .env.example: reframe TWITTER_BEARER_TOKEN and TIKTOK_RESEARCH_ACCESS_TOKEN
  as optional (they only affect API-gated discovery, not the primary
  library import + compose flow). Note the pricing reality for the X
  token. Document the new CAPCUT_YTDLP_PATH test hook.
- library/sounds/README.md: reflect the actual directory layout
  (assets/ is where imports land), mark the nested manifest.json as a
  legacy seed, and point readers at the authoritative library/manifest.json.
- .devcontainer/post-create.sh: drop the Python mention from the header
  comment now that the bootstrap is entirely Rust-native.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 61087f6ddd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/config.rs
Comment on lines +38 to +39
if let Ok(p) = std::env::var("CAPCUT_YTDLP_PATH") {
return PathBuf::from(p);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Treat empty CAPCUT_YTDLP_PATH as unset

ytdlp_path() now returns the CAPCUT_YTDLP_PATH value whenever the variable exists, even if it is an empty string. In that case downstream dependency flows break (for example, deps install reaches download_ytdlp() with an empty destination path and can panic on dest.parent().unwrap()), so users who source a .env file containing CAPCUT_YTDLP_PATH= get a hard failure instead of the default ~/.capcut-cli/bin/yt-dlp behavior.

Useful? React with 👍 / 👎.

Comment thread scripts/build-clips.sh
Comment on lines +118 to +119
--argjson sound "$(echo "$SOUND_JSON" | jq '.data.sounds[0]')" \
--argjson clips "$(echo "$CLIPS_JSON" | jq "[.data.clips[0:${#CLIP_IDS[@]}][]]")" \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Persist actual imported candidates in discovery manifest

The manifest is labeled as provenance for the generated clips, but it always stores .data.sounds[0] and the first N discovered clips rather than the candidates that were actually imported. When early ranked URLs fail import and later ones succeed (which this script explicitly supports), clips/manifest.json records different sources than the MP4s were built from, making reruns/debugging unreliable.

Useful? React with 👍 / 👎.

@scrumlord8
scrumlord8 merged commit 2a04157 into main Apr 18, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants